//; ---------------------------------------------------------------------------
//; Object 41 - springs
//; ---------------------------------------------------------------------------

static object *obj;

#define player objects[0]
extern object *objects;

void (*Spring_Index[10])() = { Spring_Main, Spring_Up, Spring_AniUp, Spring_ResetUp, Spring_LR, Spring_AniLR, Spring_ResetLR, Spring_Dwn, Spring_AniDwn, Spring_ResetDwn };

//Springs:				; XREF: Obj_Index
void Springs(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Spring_Index(pc,d0.w),d1
    //jsr	Spring_Index(pc,d1.w)
    (*Spring_Index[routine])()
    
    //bsr.w	DisplaySprite
    DisplaySprite();

    //out_of_range	DeleteObject
    if (out_of_range(obj)) { DeleteObject(); }

    //rts	
    //; ===========================================================================
}

//spring_pow:	= $30			; power of current spring
#define spring_pow 0x30

signed short SpringPowers[2] = { -0x1000, -0xA00 }; //power of red and yellow springs

//; ===========================================================================

//Spring_Main:	; Routine 0
void Spring_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;
	
    //move.l	#Map_Spring,obMap(a0)
    obj->Map = Map_Spring;
	
    //move.w	#$523,obGfx(a0)
    obj->Gfx = 0x523;

    //ori.b	#4,obRender(a0)
    obj->Render = obj->Render | 4;

    //move.b	#$10,obActWid(a0)
    obj->ActionWidth = 16;

    //move.b	#4,obPriority(a0)
    obj->Priority = 4;

    //move.b	obSubtype(a0),d0
    byte springType = obj->Subtype;

    //btst	#4,d0		; does the spring face left/right?
    //beq.s	Spring_NotLR	; if not, branch
    if ((springType & 16) == 16)
    {
        //move.b	#8,obRoutine(a0) ; use "Spring_LR" routine
	obj->Routine = 8;
	
        //move.b	#1,obAnim(a0)
        obj->Anim = 1;
	
	//move.b	#3,obFrame(a0)
        obj->Frame = 3;
	
        //move.w	#$533,obGfx(a0)
        obj->Gfx = 0x533;
	
	//move.b	#8,obActWid(a0)
        obj->ActionWidth = 8;
    }
    
    //Spring_NotLR:
    //btst	#5,d0		; does the spring face downwards?
    //beq.s	Spring_NotDwn	; if not, branch
    if ((springType & 32) == 32)
    {
        //move.b	#$E,obRoutine(a0) ; use "Spring_Dwn" routine
        obj->Routine = 14;
	
	//bset	#1,obStatus(a0)
        obj->Status = obj->Status | 2;
    }

    //Spring_NotDwn:
    //btst	#1,d0
    //beq.s	loc_DB72
    if ((springType & 2) == 2)
    {
        //bset	#5,obGfx(a0)
        obj->Gfx = obj->Gfx | 32;
    }

    //loc_DB72:
    //andi.w	#$F,d0
    //move.w	Spring_Powers(pc,d0.w),spring_pow(a0)
    ptrsetobjvariableword(spring_pow, obj, Spring_Powers[springType & 0xF]);
	
    //rts	
    //; ===========================================================================
}

//Spring_Up:	; Routine 2
void Spring_Up()
{
    //move.w	#$1B,d1
    //move.w	#8,d2
    //move.w	#$10,d3
    //move.w	obX(a0),d4
    //bsr.w	SolidObject
    SolidObject(obj, 0x1B, 8, 16, obj->X);

    //tst.b	ob2ndRout(a0)	; is Sonic on top of the spring?
    //bne.s	Spring_BounceUp	; if yes, branch
    if (obj->SecondRoutine != 0) { Spring_BounceUp(); }
	
    //rts	
    //; ===========================================================================
}

//Spring_BounceUp:
void Spring_BounceUp()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //addq.w	#8,obY(a1)
    player.Y = player.Y + 8;

    //move.w	spring_pow(a0),obVelY(a1) ; move Sonic upwards
    player.VelocityY = ptrgetobjvariableword(spring_pow, obj);

    //bset	#1,obStatus(a1)
    player.Status = player.Status | 2;

    //bclr	#3,obStatus(a1)
    player.Status = player.Status - (player.Status & 8);

    //move.b	#id_Spring,obAnim(a1) ; use "bouncing" animation
    player.Anim = id_Spring;
	
    //move.b	#2,obRoutine(a1)
    player.Routine = 2;

    //bclr	#3,obStatus(a0)
    obj->Status = obj->Status - (obj->Status & 8);
 
    //clr.b	ob2ndRout(a0)
    obj->SecondRoutine = 0;

    //sfx	sfx_Spring	; play spring sound
    
    Spring_AniUp();
}

//Spring_AniUp:	; Routine 4
void Spring_AniUp()
{
    //lea	(Ani_Spring).l,a1
    byte **springAnim = Ani_Spring;

    //bra.w	AnimateSprite
    AnimateSprite(obj, springAnim);
}

//; ===========================================================================

//Spring_ResetUp:	; Routine 6
void Spring_ResetUp()
{ 
    //move.b	#1,obNextAni(a0) ; reset animation
    obj->NextAni = 1;

    //subq.b	#4,obRoutine(a0) ; goto "Spring_Up" routine
    obj->Routine = obj->Routine - 4;

    //rts
}	
//; ===========================================================================

//Spring_LR:	; Routine 8
void Spring_LR()
{
    //move.w	#$13,d1
    //move.w	#$E,d2
    //move.w	#$F,d3
    //move.w	obX(a0),d4
    //bsr.w	SolidObject
    SolidObject(obj, 0x13, 14, 15, obj->X);

    //cmpi.b	#2,obRoutine(a0)
    //bne.s	loc_DC0C
    if (obj->Routine == 2)
    {
        //move.b	#8,obRoutine(a0)
        obj->Routine = 8;
    }
   
    //loc_DC0C:
    //btst	#5,obStatus(a0)
    //bne.s	Spring_BounceLR
    if ((obj->Status & 32) != 32) { Spring_BounceLR(); }

    //rts	
}   //; ===========================================================================

//Spring_BounceLR:
void Spring_BounceLR()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.w	spring_pow(a0),obVelX(a1) ; move Sonic to the left
    player.VelocityX = ptrgetobjvariableword(spring_pow, obj);

    //addq.w	#8,obX(a1)
    player.X = player.X + 8;

    //btst	#0,obStatus(a0)	; is object flipped?
    //bne.s	Spring_Flipped	; if yes, branch
    if ((obj->Status & 1) == 0)
    {
        //subi.w	#$10,obX(a1)
        player.X = player.X - 16;

        //neg.w	obVelX(a1)	; move Sonic to	the right
        player.VelocityX = -player.VelocityX;
    }
 
    //Spring_Flipped:
    //move.w	#$F,$3E(a1)
    setobjvariableword(0x3E, obj, 15);

    //move.w	obVelX(a1),obInertia(a1)
    player.Inertia = player.VelocityX;

    //bchg	#0,obStatus(a1)
    player.Status = (player.Status ^ 1);

    //btst	#2,obStatus(a1)
    //bne.s	loc_DC56
    if ((player.Status & 4) == 0)
    {
        //move.b	#0,obAnim(a1)	; use running animation
        player.Anim = 0;
    }

    //loc_DC56:
    //bclr	#5,obStatus(a0)
    obj->Status = obj->Status - (obj->Status & 32);

    //bclr	#5,obStatus(a1)
    player.Status = player.Status - (player.Status & 32);

    //sfx	sfx_Spring	; play spring sound
}

//Spring_AniLR:	; Routine $A
void Spring_AniLR()
{
    //lea	(Ani_Spring).l,a1
    byte **springAnim = Ani_Spring;

    //bra.w	AnimateSprite
    AnimateSprite(obj, springAnim);
}

//; ===========================================================================

//Spring_ResetLR:	; Routine $C
void Spring_ResetLR()
{
    //move.b	#2,obNextAni(a0) ; reset animation
    obj->NextAni = 2;

    //subq.b	#4,obRoutine(a0) ; goto "Spring_LR" routine
    obj->Routine = obj->Routine - 4;	
	
    //rts	
}   //; ===========================================================================

//Spring_Dwn:	; Routine $E
void Spring_Dwn()
{
    //move.w	#$1B,d1
    //move.w	#8,d2
    //move.w	#$10,d3
    //move.w	obX(a0),d4 
    signed short springX = obj->X;

    //bsr.w	SolidObject
    long playerPos = SolidObject(obj, 0x1B, 8, 16, springX);

    //cmpi.b	#2,obRoutine(a0)
    //bne.s	loc_DCA4
    if (obj->Routine == 2) 
    {
        //move.b	#$E,obRoutine(a0)
        obj->Routine = 14;
    }

    //loc_DCA4:
    //tst.b	ob2ndRout(a0)
    //bne.s	locret_DCAE
    if (obj->SecondRoutine == 0)
    {
        //tst.w	d4
	//bmi.s	Spring_BounceDwn
        if (playerPos < 0)            
        { 
            Spring_BounceDwn();
        }  
    }

    //locret_DCAE:
    //rts	
}   //; ===========================================================================

//Spring_BounceDwn:			; XREF: Spring_Dwn
void Spring_BounceDwn()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //subq.w	#8,obY(a1)
    player.Y = player.Y - 8;

    //move.w	spring_pow(a0),obVelY(a1)
    player.VelocityY = ptrgetobjvariableword(spring_pow, obj);

    //neg.w	obVelY(a1)	; move Sonic downwards
    player.VelocityY = -player.VelocityY;

    //bset	#1,obStatus(a1)
    player.Status = player.Status | 2;

    //bclr	#3,obStatus(a1)
    player.Status = player.Status - (player.Status & 8);

    //move.b	#2,obRoutine(a1)
    player.Routine = 2;

    //bclr	#3,obStatus(a0)
    obj->Status = obj->Status - (obj->Status & 8);

    //clr.b	ob2ndRout(a0)
    obj->SecondRoutine = 0;

    //sfx	sfx_Spring	; play spring sound
    
    Spring_AniDwn();
}

//Spring_AniDwn:	; Routine $10
void Spring_AniDwn()
{
    //lea	(Ani_Spring).l,a1
    byte **springAnim = Ani_Spring;

    //bra.w	AnimateSprite
    AnimateSprite(obj, springAnim);

}   //; ===========================================================================

//Spring_ResetDwn:      ; Routine $12
void Spring_ResetDwn()
{
    //move.b	#1,obNextAni(a0) ; reset animation
    obj->NextAni = 1;

    //subq.b	#4,obRoutine(a0) ; goto "Spring_Dwn" routine
    obj->Routine = obj->Routine - 4;

}   //rts	
